using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SmartLink.Domain;
using SmartLink.Domain.Entity;
using SmartLink.RedisRepository;
using SmartLink.Infrastructure;
using SmartLink.DTOS.Account;
using SmartLink.DTOS.SysBasic;
using SmartLink.DTOS.Permission;
using SmartLink.EnumLibrary;

namespace SmartLink.Infrastructure.Cache
{
    /// <summary>
    ///  用户相关数据缓存
    /// </summary>
    public class UserInfoCaches
    {
        /// <summary>
        /// 用户缓存信息集合
        /// </summary>
        private static ConcurrentDictionary<string, CurrentUserInfo> UserInfo = new ConcurrentDictionary<string, CurrentUserInfo>();
        private static ConcurrentDictionary<int, IList<int>> dicUserToRoles = new ConcurrentDictionary<int, IList<int>>();
        private static ConcurrentDictionary<int, IList<int>> dicRoleToUsers = new ConcurrentDictionary<int, IList<int>>();

        /// <summary>
        /// 缓存用户基本信息
        /// </summary>
        public static void SetLoginCache(string token, CurrentUserInfo currentUser)
        {
            int userId = JWTHelper.GetUserIdFromToken(token);
            var expiresTime = DateTime.Now.AddDays(1);
            var key = RedisKeyPre.UserToken + userId;
            //memory 缓存
            currentUser.Expires = TimeHelper.GetUnixTime(expiresTime);
            if (UserInfo.ContainsKey(key))
            {
                UserInfo[key] = currentUser;
            }
            else
            {
                UserInfo.TryAdd(key, currentUser);
            }
            //redis缓存
            RedisManager.GetInstance().HashSet(key, "userid", currentUser.UserId.ToString());
            RedisManager.GetInstance().HashSet(key, "nickname", currentUser.NickName);
            RedisManager.GetInstance().HashSet(key, "useremail", currentUser.UserEmail);
            RedisManager.GetInstance().HashSet(key, "roid", currentUser.ROID.ToString());
            RedisManager.GetInstance().HashSet(key, "oid", currentUser.OID.ToString());
            // RedisManager.GetInstance().HashSet(key, "odid", currentUser.ODID.ToString());
            RedisManager.GetInstance().HashSet(key, "token", token);
            RedisManager.GetInstance().HashSet(key, "organizationname", currentUser.OrganizationName);
            //RedisManager.GetInstance().HashSet(key, "departmentname", currentUser.DepartmentName);
            RedisManager.GetInstance().HashSet(key, "usermobile", currentUser.UserMobile);
            RedisManager.GetInstance().HashSet(key, "expires", currentUser.Expires);
            RedisManager.GetInstance().HashSet(key, "roleid", currentUser.RoleId.ToString());
            RedisManager.GetInstance().HashSet(key, "rolename", currentUser.RoleName);
            if (currentUser.UserType == (int)UserTypeEnum.车主用户)
            {
                RedisManager.GetInstance().HashSet(key, "usertype", currentUser.UserType.ToString());
                RedisManager.GetInstance().HashSet(key, "openId", currentUser.OpenID == null ? "" : currentUser.OpenID.ToString());
            }
            RedisManager.GetInstance().HashSet(key, "hasupdatedpwdself", currentUser.HasUpdatedPwdSelf.ToString());
            if (currentUser.RootOrgDescendantsIds != null)
                RedisManager.GetInstance().HashSet(key, "rootorgdescendantsids", string.Join(",", currentUser.RootOrgDescendantsIds).ToString());
            else
                RedisManager.GetInstance().HashSet(key, "rootorgdescendantsids", "");
        }

        /// <summary>
        /// 更新用户缓存信息
        /// </summary>
        public static void UpdateLoginCacheForHasUpdatedPwdSelf(CurrentUserInfo currentUser)
        {
            var expiresTime = DateTime.Now.AddDays(1);
            var key = RedisKeyPre.UserToken + currentUser.UserId;
            //memory 缓存
            currentUser.HasUpdatedPwdSelf = true;
            currentUser.Expires = TimeHelper.GetUnixTime(expiresTime);
            if (UserInfo.ContainsKey(key))
            {
                UserInfo[key] = currentUser;
            }
            else
            {
                UserInfo.TryAdd(key, currentUser);
            }
            //redis缓存
            RedisManager.GetInstance().HashSet(key, "expires", currentUser.Expires);
            RedisManager.GetInstance().HashSet(key, "hasupdatedpwdself", currentUser.HasUpdatedPwdSelf.ToString());
        }

        /// <summary>
        /// 获取缓存用户基本信息
        /// </summary>
        public static CurrentUserInfo GetUserInfoCache(string token)
        {
            int userId = JWTHelper.GetUserIdFromToken(token);
            return GetUserInfoCache(userId);
        }
        /// <summary>
        /// 获取缓存用户基本信息
        /// </summary>
        public static CurrentUserInfo GetUserInfoCache(int userId)
        {
            var key = RedisKeyPre.UserToken + userId;
            if (UserInfo.ContainsKey(key))
            {
                return UserInfo[key];
            }

            if (string.IsNullOrEmpty(RedisManager.GetInstance().HashGet(key, "userid")))
            {
                return null;
            }
            var currentUser = new CurrentUserInfo
            {
                UserId = Convert.ToInt32(RedisManager.GetInstance().HashGet(key, "userid")),
                NickName = RedisManager.GetInstance().HashGet(key, "nickname"),
                UserEmail = RedisManager.GetInstance().HashGet(key, "useremail"),
                AccountName = RedisManager.GetInstance().HashGet(key, "username"),
                Expires = RedisManager.GetInstance().HashGet(key, "expires"),
                ROID = Convert.ToInt32(RedisManager.GetInstance().HashGet(key, "roid")),
                OID = Convert.ToInt32(RedisManager.GetInstance().HashGet(key, "oid")),
                // ODID = Convert.ToInt32(RedisManager.GetInstance().HashGet(key, "odid")),
                OrganizationName = RedisManager.GetInstance().HashGet(key, "organizationname"),
                // DepartmentName = RedisManager.GetInstance().HashGet(key, "departmentname"),
                RoleName = RedisManager.GetInstance().HashGet(key, "rolename"),
                UserMobile = RedisManager.GetInstance().HashGet(key, "usermobile"),
                UserType = Convert.ToInt32(RedisManager.GetInstance().HashGet(key, "usertype")),
                OpenID = RedisManager.GetInstance().HashGet(key, "openId"),
                HasUpdatedPwdSelf = Convert.ToBoolean(RedisManager.GetInstance().HashGet(key, "hasupdatedpwdself"))
                //RootOrgDescendantsIds = Array.ConvertAll(RedisManager.GetInstance().HashGet(key, "rootorgdescendantsids").Split(','), a => Int32.Parse(a))
            };
            if (currentUser.UserType == (int)UserTypeEnum.平台用户)
                currentUser.RootOrgDescendantsIds = Array.ConvertAll(RedisManager.GetInstance().HashGet(key, "rootorgdescendantsids").Split(','), a => Int32.Parse(a));

            UserInfo[key] = currentUser;
            return currentUser;
        }
        /// <summary>
        /// 获取token过期时间
        /// </summary>
        /// <param name="token"></param>
        public static string GetUserTokenExpires(string token)
        {
            int userId = JWTHelper.GetUserIdFromToken(token);
            var key = RedisKeyPre.UserToken + userId;
            var value = RedisManager.GetInstance().HashGet(key, "expires");//过期时间
            return value;
        }
        /// <summary>
        /// 删除token的缓存 
        /// </summary>
        /// <param name="token"></param>
        /// <param name="flag">1 PC,2 APP </param>
        /// <returns></returns>
        public static bool TokenDelete(string token, PlatformEnum? flag = PlatformEnum.PC)
        {
            int userId = JWTHelper.GetUserIdFromToken(token);
            return TokenDelete(userId, flag);
        }
        /// <summary>
        /// 删除token的缓存 
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="flag">1 PC,2 APP </param>
        /// <returns></returns>
        public static bool TokenDelete(int userId, PlatformEnum? flag = PlatformEnum.PC)
        {
            string Key = RedisKeyPre.UserToken + userId;
            if (flag.HasValue)
            {
                if (flag.Value == PlatformEnum.PC)
                    return RedisManager.GetInstance().HashDelete(Key, "token");
                else
                    return RedisManager.GetInstance().HashDelete(Key, "appToken");
            }
            else
            {
                return RedisManager.GetInstance().HashDelete(Key, "token") && RedisManager.GetInstance().HashDelete(Key, "appToken");
            }
        }
        public static string GetRedisToken(string token)
        {
            try
            {
                string tokenKey = "token";
                int userId = JWTHelper.GetUserIdFromToken(token);
                bool isApp = JWTHelper.GetIsAppFromToken(token);
                if (isApp)
                    tokenKey = "appToken";
                string Key = RedisKeyPre.UserToken + userId;
                return RedisManager.GetInstance().HashGet(Key, tokenKey);
            }
            catch (Exception ex)
            {
                return "DecoedeError";
            }
        }

        public static bool SetExpires(int userId, DateTime? expiresTime = null)
        {
            var key = RedisKeyPre.UserToken + userId;
            if (!expiresTime.HasValue) expiresTime = DateTime.MinValue;
            var expires = TimeHelper.GetUnixTime(expiresTime.Value);
            if (UserInfo.ContainsKey(key))
            {
                UserInfo[key].Expires = expires;
            }
            return RedisManager.GetInstance().HashSet(key, "expires", expires);
        }
        public static bool SetUserSingleInfo(string key, string hashKey, string value)
        {
            return RedisManager.GetInstance().HashSet(key, hashKey, value);
        }
        /// <summary>
        /// 设置用户token
        /// </summary>
        /// <param name="key"></param>
        /// <param name="hashKey"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public static bool SetUserToken(string key, string hashKey, string token)
        {
            return RedisManager.GetInstance().HashSet(key, hashKey, token);
        }
        public static bool RemoveUserInfo(int userId)
        {
            var key = RedisKeyPre.UserToken + userId;
            CurrentUserInfo curInfo = null;
            if (UserInfo.ContainsKey(key))
                UserInfo.TryRemove(key, out curInfo);
            RedisManager.GetInstance().KeyDelete(key);
            return true;
        }


        public static void SetActionPermissionCache(int userId, UserPermissionDTO userPermission)
        {
            string key = RedisKeyPre.UserActionPermission + userId;
            RedisManager.GetInstance().StringSet(key, JsonEx.SerializeObject(userPermission));
        }
        public static UserPermissionDTO GetActionPermissionCahce(int userId)
        {
            string key = RedisKeyPre.UserActionPermission + userId;
            return JsonEx.DeserializeObject<UserPermissionDTO>(RedisManager.GetInstance().StringGet(key));
        }
        public static void RemoveActionPermissionCache(int userId)
        {
            string key = RedisKeyPre.UserActionPermission + userId;
            RedisManager.GetInstance().KeyDelete(key);
        }


        public static void SetRightsMenus(int userId, TreeNode menuNode)
        {
            string key = RedisKeyPre.UserMenus + userId;
            RedisManager.GetInstance().StringSet(key, JsonEx.SerializeObject(menuNode));
        }
        public static TreeNode GetRightsMenus(int userId)
        {
            string key = RedisKeyPre.UserMenus + userId;
            return JsonEx.DeserializeObject<TreeNode>(RedisManager.GetInstance().StringGet(key));
        }
        public static void RemoveRightsMenus(int userId)
        {
            string key = RedisKeyPre.UserMenus + userId;
            RedisManager.GetInstance().KeyDelete(key);
        }

        public static void SetRightsActions(int userId, IList<string> actions)
        {
            string key = RedisKeyPre.UserActionPermission + userId;
            RedisManager.GetInstance().StringSet(key, JsonEx.SerializeObject(actions));
        }
        public static IList<string> GetRightsActions(int userId)
        {
            string key = RedisKeyPre.UserActionPermission + userId;
            return JsonEx.DeserializeObject<IList<string>>(RedisManager.GetInstance().StringGet(key));
        }
        public static void RemoveRightsActions(int userId)
        {
            string key = RedisKeyPre.UserActionPermission + userId;
            RedisManager.GetInstance().KeyDelete(key);
        }

        public static void SetDataRights(int userId, IList<int> dataRights)
        {
            string key = RedisKeyPre.UserDatas + userId;
            RedisManager.GetInstance().StringSet(key, JsonEx.SerializeObject(dataRights));
        }
        public static IList<int> GetDataRights(int userId)
        {
            string key = RedisKeyPre.UserDatas + userId;
            return JsonEx.DeserializeObject<IList<int>>(RedisManager.GetInstance().StringGet(key));
        }
        public static void RemoveDataRights(int userId)
        {
            string key = RedisKeyPre.UserDatas + userId;
            RedisManager.GetInstance().KeyDelete(key);
        }


        /// <summary>
        /// 缓存角色用户关系
        /// </summary>
        public static void RefreshUserRoleRelation(int userId, IList<int> roles)
        {
            IList<int> preUserRoles = new List<int>();
            if (dicUserToRoles.ContainsKey(userId))
                preUserRoles = dicUserToRoles[userId];
            IList<int> lostRolses = preUserRoles.Except(roles).ToList();
            dicUserToRoles[userId] = roles;
            foreach (int lostRole in lostRolses)
            {
                if (dicRoleToUsers.ContainsKey(lostRole))
                {
                    dicRoleToUsers[lostRole].Remove(userId);
                }
            }
        }
        public static void AddUserRoleRelation(int userId, int roleId, RoleUser type)
        {
            if (type == RoleUser.Role)
            {
                if (!dicRoleToUsers.ContainsKey(roleId))
                {
                    IList<int> users = new List<int>();
                    users.Add(userId);
                    dicRoleToUsers[roleId] = users;
                }
                else
                {
                    if (!dicRoleToUsers[roleId].Contains(userId))
                        dicRoleToUsers[roleId].Add(userId);
                }
            }

            if (type == RoleUser.User)
            {
                if (!dicUserToRoles.ContainsKey(userId))
                {
                    IList<int> roles = new List<int>();
                    roles.Add(roleId);
                    dicUserToRoles[userId] = roles;
                }
                else
                {
                    if (!dicUserToRoles[userId].Contains(roleId))
                        dicUserToRoles[userId].Add(roleId);
                }
            }

        }
        public static void RemoveUserCacheByRole(int roleId)
        {
            if (dicRoleToUsers.ContainsKey(roleId))
            {
                IList<int> userIds = dicRoleToUsers[roleId];
                foreach (int userId in userIds)
                {
                    UserInfoCaches.RemoveUserRightsCache(userId);
                }
            }
        }

        public static void RemoveUserRightsCache(int userId)
        {
            RemoveDataRights(userId);
            RemoveRightsActions(userId);
            RemoveRightsMenus(userId);
        }

    }


    public enum RoleUser
    {
        User,
        Role
    }

}
